<?php
/**                                                                                                                                         
 * IpbXmlRpcClient - XMLRPC Client for IPB 3.0+                                                                                                         
 *                                                                                                                                          
 * Copyright (c) 2011, Igor F. Zinkovsky (admin@mysterria.com).                                                                                                         
 * All rights reserved.                                                                                                                     
 *                                                                                                                                          
 * @author     Igor F. Zinkovsky                                                                                                               
 *                                                                                
 */                                                 

require_once('IXR_Library.php');

class IpbXmlRpcClient {
	private $debug = false;
    private $lastError = null;
    
    public function __construct($forumUrl, $apiKey, $apiModule = 'ipb') {
        $this->url = $forumUrl."/interface/board/index.php";
        $this->apiKey = $apiKey;
        $this->apiModule = $apiModule;
    }
    
	public function setDebug($debug){
		$this->debug = (bool)$debug; 
	}
	
    private function actionPreExecute() {
        $this->lastError = null;
    }
    
    private function populateLastError($r) {
        $this->lastError = 'faultCode=>'.$r['faultCode'].'; faultString=>'.$r['faultString'];
    }
    
    public function getLastError() {
        return $this->lastError;
    }
	
	private function sendRequest($rpcMethod, $rpcParams=array(), $debug=false){
		/* These params must be filled in any query to IPB XMLRPC API */
		$rpcParams['api_key'] = $this->apiKey;
		$rpcParams['api_module'] = $this->apiModule;
		
		/* Using XMLRPC proto client to make a request */
		$client = new IXR_Client($this->url);
		$client->debug = $debug || $this->debug;
		$reqStatus = $client->query($rpcMethod, $rpcParams);
   		if(!$reqStatus){
			$this->lastError = 'An error occurred - '.$client->getErrorCode().":".$client->getErrorMessage();
			return false;
		}
		return $client->getResponse(); 
	}
    
	/**
	 * Post a new topic to forum
	 * @param array $data
	 * @return 
	 */
    public function postTopic($data) {
        $this->actionPreExecute();
        
		$reqParams = array(
				'member_key'=>$data['member_id'],
				//'member_field' =>'member_id',
            
				'forum_id'=>$data['forum_id'],
				'topic_title'=>$data['topic_title'], 
				'topic_description'=>$data['topic_description'], 
				'post_content'=>$data['post_content']
        );
		
		/* Protocol layer */		
		$r = $this->sendRequest('postTopic', $reqParams);
		if($r === false) return $r;
						
		/* Application layer error handling and response parsing */
		if ($r['result'] == 'success') {
            return $r['topic_id'];
        } else {
            $this->populateLastError($r);
            return false;
        }
    }
	
	/**
	 * Brief forum info returned as a hash
	 * @return 
	 */
	public function helloBoard(){
		$this->actionPreExecute();
		
		/* Protocol layer */		
		$r = $this->sendRequest('helloBoard', array());
		if($r === false) return $r;
						
		/* Application layer error handling and response parsing */
		if ( !isset($r['faultCode']) ) {
			return $r;
        } else {
            $this->populateLastError($r);
            return false;
        }
	}
	
	/**
	 * Posts reply to an already existing topic
	 * 
	 * ============ WARNING!!! =============
	 * To use guest comments apply a extended_xmlrpc patch.
	 * Otherwise you'll get no-user error message when sending
	 * no member_id field.
	 * =====================================
	 * 
	 * @return
	 */
	public function postReply($data = array()){
		$this->actionPreExecute();
				
		if( isset($data['member_id']) ){
			$data['member_key'] = $data['member_id'];
			unset($data['member_id']); 
		}
						
		/* Protocol layer */
		$r = $this->sendRequest('postReply', $data);
		if($r === false) return $r; //it has it's own mechanism to populate lastError
						
		/* Application layer error handling and response parsing */
		if ( !isset($r['faultCode']) ) {
			return $r;
        } else {
            $this->populateLastError($r);
            return false;
        }
	}
	
	/**
	 * ============ WARNING!!! ============= 
	 * This is not a standard method and it is 
	 * unavailable in unpatched version of IPB.
	 * To use this method apply a extended_xmlrpc patch 
	 * bundled with this class to your forum sources.
	 * =====================================
	 * @return 
	 */
	public function fetchTopicInfo($data){
		$this->actionPreExecute();
		
		/* Protocol layer */		
		$r = $this->sendRequest('fetchTopicInfo', $data);
		if($r === false) return $r;
						
		/* Application layer error handling and response parsing */
		if ( !isset($r['faultCode']) ) {
			return $r;
        } else {
            $this->populateLastError($r);
            return false;
        }
	}
	
	/**
	 * ============ WARNING!!! ============= 
	 * This is not a standard method and it is 
	 * unavailable in unpatched version of IPB.
	 * To use this method apply a extended_xmlrpc patch 
	 * bundled with this class to your forum sources.
	 * =====================================
	 * @return 
	 */
	public function fetchTopicsInfo($data){
		$this->actionPreExecute();
		
		/* Protocol layer */		
		$r = $this->sendRequest('fetchTopicsInfo', $data);
		if($r === false) return $r;
						
		/* Application layer error handling and response parsing */
		if ( !isset($r['faultCode']) ) {
			return $r;
        } else {
            $this->populateLastError($r);
            return false;
        }
	}
	
	/**
	 * ============ WARNING!!! ============= 
	 * This is not a standard method and it is 
	 * unavailable in unpatched version of IPB.
	 * To use this method apply a extended_xmlrpc patch 
	 * bundled with this class to your forum sources.
	 * =====================================
	 * @return 
	 */
	public function fetchReplies($data){
		$this->actionPreExecute();
		
		/* Some fixes by the way */
		if(!isset($data['order_field'])) $data['order_field'] = 'pid';
		if(!isset($data['offset'])) $data['offset'] = 0;
		if(!isset($data['limit'])) $data['limit'] = 1000; /* Enough to be default */
		
		/* Protocol layer */		
		$r = $this->sendRequest('fetchReplies', $data);
		if($r === false) return $r;
						
		/* Application layer error handling and response parsing */
		if ( !isset($r['faultCode']) ) {
			return $r;
        } else {
            $this->populateLastError($r);
            return false;
        }
	}
	
	
	public function fetchTopics($data){
		$this->actionPreExecute();
		
		/* Without these defaults you'll get transport error with response code different then 200 OK */
		if(!isset($data['order_field'])) $data['order_field'] = 't.tid';
		if(!isset($data['offset'])) $data['offset'] = '0';
		if(!isset($data['limit'])) $data['limit'] = '0';
		
		/* Protocol layer */		
		$r = $this->sendRequest('fetchTopics', $data);
		if($r === false) return $r;
						
		/* Application layer error handling and response parsing */
		if ( !isset($r['faultCode']) ) {
			return $r;
        } else {
            $this->populateLastError($r);
            return false;
        }
	}
}

?>
